package graphs;
/**
 * A city is identified by its name, a single uppercase character.
 * Conversions to/from characters are handled by {@link #getName()}
 * and {@link #valueOf(char)}, respectively.
 * <p>
 * Package members are also given access to an identity relationship
 * between cities and numbers: they can converts between
 * <code>City</code> instances and numbers using {@link #valueOf(int)}
 * and {@link #getIndex()}. This special relationship is used by the
 * {@link com.waldura.tw.DenseRoutesMap DensesRoutesMap} to store
 * cities in an array.
 * 
 * @author Renaud Waldura &lt;renaud+tw@waldura.com&gt;
 * @version $Id: City.java 2367 2007-08-20 21:47:25Z renaud $
 */
public final class City implements Comparable<City> {
  /**
   * The largest possible number of cities.
   */
  public static final int     MAX_NUMBER = 26;
  private static final City[] cities     = new City[MAX_NUMBER];
  static {
    // initialize all City objects
    for (char c = 'A'; c <= 'Z'; c++) {
      cities[getIndexForName(c)] = new City(c);
    }
  }
  
  private static int getIndexForName(char name) {
    return name - 'A';
  }
  
  private static char getNameForIndex(int index) {
    return (char) ('A' + index);
  }
  public static final City A = City.valueOf('A');
  public static final City B = City.valueOf('B');
  public static final City C = City.valueOf('C');
  public static final City D = City.valueOf('D');
  public static final City E = City.valueOf('E');
  public static final City F = City.valueOf('F');
  
  public static City valueOf(char name) {
    if (name < 'A' || name > 'Z') {
      throw new IllegalArgumentException("Invalid city name: " + name);
    }
    return cities[getIndexForName(name)];
  }
  
  /*
   * Package members only.
   */
  public static City valueOf(int n) {
    if (n < 0 || n > 25) {
      throw new IllegalArgumentException("Invalid city number: " + n);
    }
    return valueOf(getNameForIndex(n));
  }
  private final char name;
  
  /**
   * Private constructor.
   * 
   * @param name
   */
  private City(char name) {
    this.name = name;
  }
  
  public char getName() {
    return name;
  }
  
  /*
   * Package members only.
   */
  public int getIndex() {
    return getIndexForName(name);
  }
  
  /**
   * @see java.lang.Object#toString()
   */
  public String toString() {
    return String.valueOf(name);
  }
  
  /**
   * Two cities are considered equal if they are the same object, or
   * their names are the same.
   * 
   * @see java.lang.Object#equals(Object)
   */
  public boolean equals(Object o) {
    return this == o || equals((City) o);
  }
  
  private boolean equals(City c) {
    return this.name == c.name;
  }
  
  /**
   * Compare two cities by name.
   * 
   * @see java.lang.Comparable#compareTo(Object)
   */
  public int compareTo(City c) {
    return this.name - c.name;
  }
}
